
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_ssi.h"
#include "inc/hw_sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/gpio.h"
#include "driverlib/ssi.h"
#include "driverlib/pin_map.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/rom.h"
#include "buttonPress.h"

// Globals
tBoolean g_fnc; // is function button pressed?
float g_tempo = 2;
unsigned long long g_count;
tBoolean g_toggle;
unsigned int g_sw = 0; // Switch tracker
unsigned int g_LEDON[16] = { 0 }; // Which Leds are on
unsigned long testy = 1;
unsigned long ulPortBase, ulPin;

///////////////////////////
// * Handles button presses.
// * @int btn: 0 - 15
// *
///////////////////////////
void handleBtn(int btn, int event) {
	btn += 1;
	effectButtonPress(); // Deal with effects
	//Function button is pressed!
	if (g_fnc) {
		switch (event) {

		case 1: // Set the LED
			ulPin = btn < 5 ? GREEN1 : btn < 9 ? GREEN2 :
					btn < 13 ? GREEN3 : GREEN4;
			ulPortBase = btn < 5 ? GPIO_PORTB_BASE : btn < 9 ? GPIO_PORTD_BASE :
							btn < 13 ? GPIO_PORTD_BASE : GPIO_PORTF_BASE;
			GPIOPinWrite(GPIO_PORTB_BASE, GREEN1, 0);
			GPIOPinWrite(GPIO_PORTD_BASE, GREEN2 | GREEN3, 0);
			GPIOPinWrite(GPIO_PORTF_BASE, GREEN4, 0);
			GPIOPinWrite(ulPortBase, ulPin, ulPin);
			break;
		case 2: // Clear the LED
			GPIOPinWrite(GPIO_PORTB_BASE, GREEN1, 0);
			GPIOPinWrite(GPIO_PORTD_BASE, GREEN2 | GREEN3, 0);
			GPIOPinWrite(GPIO_PORTF_BASE, GREEN4, 0);
			break;
		}
	} else {
		switch (event) {
		case 1: // Set the LED
			ulPin = btn < 5 ? BLUE1 : btn < 9 ? BLUE2 :
					btn < 13 ? BLUE3 : BLUE4;
			ulPortBase = btn < 5 ? GPIO_PORTD_BASE : btn < 9 ? GPIO_PORTD_BASE :
							btn < 13 ? GPIO_PORTE_BASE : GPIO_PORTF_BASE;
			GPIOPinWrite(GPIO_PORTD_BASE, BLUE1 | BLUE2, 0);
			GPIOPinWrite(GPIO_PORTE_BASE, BLUE3, 0);
			GPIOPinWrite(GPIO_PORTF_BASE, BLUE4, 0);
			GPIOPinWrite(ulPortBase, ulPin, ulPin);
			break;
		case 2: // Clear the LED
			GPIOPinWrite(GPIO_PORTD_BASE, BLUE1 | BLUE2, 0);
			GPIOPinWrite(GPIO_PORTE_BASE, BLUE3, 0);
			GPIOPinWrite(GPIO_PORTF_BASE, BLUE4, 0);
			break;
		}
	}
}

void returnTempo(unsigned int bpm) {
//	g_tempo = bpm/60;

}

/////
// * Timer0 Handler
// * Deals with writing sound to DAC
////

void Timer0IntHandler(void) {
	TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
	unsigned long ulData = 0x2 << 12;

	// Handle Tempo LED. COUNT DOWN
	if (!g_count) {
		g_count = g_tempo * 4410 / 2;
	} else {
		g_count -= 1;
	}
	if (g_toggle) {
		GPIOPinWrite(GPIO_PORTF_BASE, LEDTMPO, LEDTMPO);
		g_toggle = 0;
	} else {
		GPIOPinWrite(GPIO_PORTF_BASE, LEDTMPO, 0);
		g_toggle = 1;
	}
	// Write something to DAC!
	switch (g_sw) {
	case 1:
		ulData |= 0xFFF;
		break;
	case 2:
		ulData |= 0xFF0;
		break;
	case 3:
		ulData |= 0xF0F;
		break;
	case 4:
		ulData |= 0x000;
		break;
	}
//	SSIDataPut(SSI2_BASE, ulData);
}

///////
// * Timer1 Handler
// * WOOOOSH
///////
void Timer1IntHandler(void) {
	if (g_sw < 4) {
		g_sw++;
	} else {
		g_sw = 1;
	}
	TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
	//Is function button pressed?
	if (GPIOPinRead(GPIO_PORTB_BASE, FNCBTN)) {
		g_fnc = 1;
	} else {
		g_fnc = 0;
	}
	switch (g_sw) {
	// Change 'active' row
	case 1: // Bottom row
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH1, SWITCH1);
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH2, 0);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH3, 0);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH4, 0);
		break;
	case 2: // Second from bottom
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH1, 0);
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH2, SWITCH2);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH3, 0);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH4, 0);
		break;
	case 3: // Second from top
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH1, 0);
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH2, 0);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH3, SWITCH3);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH4, 0);
		break;
	case 4: // Top row
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH1, 0);
		GPIOPinWrite(GPIO_PORTD_BASE, SWITCH2, 0);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH3, 0);
		GPIOPinWrite(GPIO_PORTF_BASE, SWITCH4, SWITCH4);
	}
//LFO sine wave lookup table

	// Wait until high is read on SWITCHGND pins.
	// Write low to corresponding LEDGND then handle the
	// button press
	if (ROM_GPIOPinRead (GPIO_PORTB_BASE, SWTGND4)) { //1st row
		if (&g_LEDON[4 * (g_sw - 1)]) {
			handleBtn(4 * (g_sw - 1), 1);
			ROM_GPIOPinWrite (GPIO_PORTC_BASE,
					LEDGND1 | LEDGND2 | LEDGND3 | LEDGND4,
					LEDGND1 | LEDGND2 | LEDGND3);
		}
		g_LEDON[4 * (g_sw - 1)] = 1;
	} else {
		handleBtn(0, 2);
		g_LEDON[4 * (g_sw - 1)] = 0;
	}
	if (testy = GPIOPinRead(GPIO_PORTB_BASE, SWTGND3)) { //2nd row
		if (&g_LEDON[4 * (g_sw - 1) + 1]) {
			handleBtn(4 * (g_sw - 1) + 1, 1);
			ROM_GPIOPinWrite (GPIO_PORTC_BASE,
					LEDGND1 | LEDGND2 | LEDGND3 | LEDGND4, ~LEDGND3);
		}
		g_LEDON[4 * (g_sw - 1) + 1] = 1;
	} else {
		handleBtn(0, 2);
		g_LEDON[4 * (g_sw - 1) + 1] = 0;
	}
	if (testy = GPIOPinRead(GPIO_PORTA_BASE, SWTGND2)) { //2nd row from right
		if (&g_LEDON[4 * (g_sw - 1) + 2]) {
			handleBtn(4 * (g_sw - 1) + 2, 1);
			ROM_GPIOPinWrite (GPIO_PORTC_BASE,
					LEDGND1 | LEDGND2 | LEDGND3 | LEDGND4, ~LEDGND2);
		}
		g_LEDON[4 * (g_sw - 1) + 2] = 1;
	} else {
		g_LEDON[4 * (g_sw - 1) + 2] = 0;
		handleBtn(0, 2);
	}
	if (testy = GPIOPinRead(GPIO_PORTA_BASE, SWTGND1)) { //rightmost row
		if (&g_LEDON[4 * (g_sw - 1) + 3]) {
			handleBtn(4 * (g_sw - 1) + 3, 1);
			ROM_GPIOPinWrite (GPIO_PORTC_BASE,
					LEDGND1 | LEDGND2 | LEDGND3 | LEDGND4, ~LEDGND1);

		}
		g_LEDON[4 * (g_sw - 1) + 3] = 1;
	} else {
		handleBtn(0, 2);
		g_LEDON[4 * (g_sw - 1) + 3] = 0;
	}
}

void doConfig(void) {
	unsigned long ulPeriod, ulDACPeriod;
	ROM_FPULazyStackingEnable ();

	// Configure the DAC output timer - Timer 0
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_TIMER0);
	ROM_TimerConfigure (TIMER0_BASE, TIMER_CFG_PERIODIC);
	ulDACPeriod = (ROM_SysCtlClockGet () / 44100); // 44.1 kHz for DAC samples
	ROM_TimerLoadSet (TIMER0_BASE, TIMER_A, ulDACPeriod);

	// Enable Timer
	ROM_TimerEnable (TIMER0_BASE, TIMER_A);

	// Set up interrupt
	ROM_IntPrioritySet (INT_TIMER0A, 0x00);
	ROM_IntEnable (INT_TIMER0A);
	ROM_TimerIntEnable (TIMER0_BASE, TIMER_TIMA_TIMEOUT);

	// Timer1A for polling buttons on the 4x4
	ROM_SysCtlClockSet (
			SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ
					| SYSCTL_OSC_MAIN);
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_TIMER1);
	ROM_TimerConfigure (TIMER1_BASE, TIMER_CFG_A_PERIODIC);
	ulPeriod = (ROM_SysCtlClockGet () / 40000);
	ROM_TimerLoadSet (TIMER1_BASE, TIMER_A, ulPeriod - 1);
	ROM_IntEnable (INT_TIMER1A);
	ROM_TimerIntEnable (TIMER1_BASE, TIMER_TIMA_TIMEOUT);
	ROM_TimerEnable (TIMER1_BASE, TIMER_A);

	//Disable unused ports
	ROM_SysCtlPeripheralDisable (SYSCTL_PERIPH_I2S0);
	ROM_SysCtlPeripheralDisable (SYSCTL_PERIPH_UART0);
	ROM_SysCtlPeripheralDisable (SYSCTL_PERIPH_I2C);

	//Enable GPIO ports A-F
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOA);
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOB);
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOC);
//	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOD); // This Port already configured in main.
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOE);
	ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOF);

	//Enable SSI Ports 1 and 2
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);

	// Config SSI
	GPIOPinConfigure(GPIO_PB4_SSI2CLK);
	GPIOPinConfigure(GPIO_PB5_SSI2FSS);
	GPIOPinConfigure(GPIO_PB6_SSI2RX);
	SSIConfigSetExpClk(DAC_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
			SSI_MODE_MASTER, SysCtlClockGet() / 4, 16);
	SSIEnable(DAC_BASE);
	SSIEnable(SD_BASE);

	// Config I/O on PORTA
	ROM_GPIOPinTypeGPIOInput (GPIO_PORTA_BASE,
			SDTx | SDClk | SWTGND1 | SWTGND2);
	ROM_GPIOPinTypeSSI (SD_BASE, SDFss | SDRx);

	// Config I/O on PORTB
	ROM_GPIOPinTypeGPIOInput (GPIO_PORTB_BASE,
			FNCBTN | LOOPBTN | SWTGND3 | SWTGND4);
	ROM_GPIOPinTypeSSI (GPIO_PORTB_BASE, DACClk | DACFss | DACRx);
	ROM_GPIOPinTypeGPIOOutput (GPIO_PORTB_BASE, GREEN1);

	// Config I/O on PORTC
	ROM_GPIOPinTypeGPIOOutput (GPIO_PORTC_BASE,
			LEDGND4 | LEDGND3 | LEDGND2 | LEDGND1);

	// Config I/O on PORTD
	ROM_GPIOPinTypeGPIOOutput (GPIO_PORTD_BASE, BLUE1 | GREEN2 | BLUE2);
	ROM_GPIODirModeSet (GPIO_PORTD_BASE, SWITCH1 | SWITCH2, GPIO_DIR_MODE_OUT);

	// Config I/O on PORTE
	ROM_GPIOPinTypeGPIOInput (GPIO_PORTE_BASE,
			POT1 | POT2 | POT3 | POT4 | POT5);
	ROM_GPIOPinTypeGPIOOutput (GPIO_PORTE_BASE, BLUE3);

	// Config I/O on PORTF
	// Unlock NMI pins
	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;
	HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
	ROM_GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE, GREEN4 | BLUE4 | LEDTMPO);
	ROM_GPIODirModeSet (GPIO_PORTF_BASE, SWITCH3 | SWITCH4, GPIO_DIR_MODE_OUT);

	// Enable weak pull-downs on SWT outs
	ROM_GPIOPadConfigSet (GPIO_PORTD_BASE, SWITCH1 | SWITCH2, GPIO_STRENGTH_2MA,
			GPIO_PIN_TYPE_STD_WPD);
	ROM_GPIOPadConfigSet (GPIO_PORTF_BASE, SWITCH3 | SWITCH4, GPIO_STRENGTH_2MA,
			GPIO_PIN_TYPE_STD_WPD);

	// And on the grounds (tie LEDGNDs high, SWTGNDs low)
	ROM_GPIOPadConfigSet (GPIO_PORTC_BASE,
			LEDGND1 | LEDGND2 | LEDGND3 | LEDGND4, GPIO_STRENGTH_2MA,
			GPIO_PIN_TYPE_STD_WPU);
	ROM_GPIOPadConfigSet (GPIO_PORTA_BASE, SWTGND1 | SWTGND2, GPIO_STRENGTH_2MA,
			GPIO_PIN_TYPE_STD_WPD);
	ROM_GPIOPadConfigSet (GPIO_PORTB_BASE, SWTGND3 | SWTGND4, GPIO_STRENGTH_2MA,
			GPIO_PIN_TYPE_STD_WPD);
	ROM_IntMasterEnable ();

	// SPI pull-up on chip-select
	GPIOPadConfigSet(GPIO_PORTB_BASE, DACFss, GPIO_STRENGTH_2MA,
			GPIO_PIN_TYPE_STD_WPU);
}

//int main(void) { //checkButtons
//	// Config Timers
//	doConfig();
//
////	IntMasterEnable();
//	while (1)
//		;
//
//}

